using System;
using System.Collections.Generic;
using System.Text;

namespace Instedd.Labs.Geo.Library.Kml.Styles
{
    public class Color
    {
        internal Color(double opacityPercent, int r, int g, int b)
        {
            this.Opacity = opacityPercent;
            this.R = r;
            this.G = g;
            this.B = b;
        }

        public static Color Create(int r, int g, int b)
        {
            return Create(100, r, g, b);
        }

        public static Color Create(double opacityPercent, int r, int g, int b)
        {
            return new Color(opacityPercent, r, g, b);
        }

        private double opacity;

        public double Opacity
        {
            get { return opacity; }
            set 
            {
                if (value > 100d || value < 0d)
                {
                    throw new ArgumentException(string.Format("The opacity value {0} is invalid. The value must be between 0 and 100", value));
                }

                this.opacity = value; 
            }
        }

        private static void AssertColorComponentValue(int colorComponentValue, string colorComponentName)
        {
            if (colorComponentValue < 0 || colorComponentValue > 255)
            {
                throw new ArgumentException(string.Format("The {0} color component value {1} is invalid. The value must be between 0 and 255", colorComponentName, colorComponentValue));
            }
        }

        public Color SetOpacity(double opacityPercent)
        {
            this.Opacity = opacityPercent;
            return this;
        }

        private int r;

        public int R
        {
            get { return r; }
            private set 
            {
                AssertColorComponentValue(value, "Red");
                this.r = value; 
            }
        }

        private int g;

        public int G
        {
            get { return g; }
            private set
            {
                AssertColorComponentValue(value, "Green");
                this.g = value;
            }
        }

        private int b;
        public int B
        {
            get { return b; }
            private set
            {
                AssertColorComponentValue(value, "Blue");
                this.b = value;
            }
        }

        public override string ToString()
        {
            double normalizedOpacityPercent = this.opacity > 1 ? this.opacity / 100 : this.opacity;
            return string.Concat(
                ConvertToHexColorComponent((int)(255 * normalizedOpacityPercent)),
                ConvertToHexColorComponent(this.B),
                ConvertToHexColorComponent(this.G),
                ConvertToHexColorComponent(this.R));
        }

        private string ConvertToHexColorComponent(int colorComponentValue)
        {
            string colorComponent = colorComponentValue.ToString("X");

            if (colorComponent.Length == 1)
            {
                return string.Concat("0", colorComponent);
            }

            return colorComponent;
        }

        public static Color White { get { return Color.Create(0xff, 0xff, 0xff); } }
        public static Color Black { get { return Color.Create(0x00, 0x00, 0x00); } }
    }
}